﻿using Assets.Scripts.Bvh.Common;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine;
using Assets.Scripts.Bvh.Cpu;

namespace Assets.Scripts.Bvh.Cpu
{
    class CpuRunner
    {
        private List<AABB> aabbs;
        private RadixTreeNode[] debugNodes;

        public void Run()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            // 获得全局三角形
            TrianglesTracker.UpdateSceneTriangles();
            stopwatch.Stop();
            var t1 = stopwatch.ElapsedMilliseconds;

            var sceneAABB = TrianglesTracker.sceneAABB;
            var tris = TrianglesTracker.sceneTriangles;
            var aabbs = TrianglesTracker.sceneTrianglesAABBs;

            stopwatch.Reset();
            stopwatch.Start();
            //从AABB数组中构建节点数据，计算叶子节点莫顿码
            var leafNodes = MortonCoder.PrepareData(aabbs, sceneAABB);
            stopwatch.Stop();
            var t2 = stopwatch.ElapsedMilliseconds;

            var radixBuilder = new RadixTreeBuilder(leafNodes);

            stopwatch.Reset();
            stopwatch.Start();
            //先对莫顿码进行排序
            radixBuilder.QuickSort();
            leafNodes = radixBuilder.leafNodes;
            stopwatch.Stop();
            var t3 = stopwatch.ElapsedMilliseconds;

            stopwatch.Reset();
            stopwatch.Start();
            //再计算基数树
            var interiorNodes = radixBuilder.BuildRadixTree();
            stopwatch.Stop();
            var t4 = stopwatch.ElapsedMilliseconds;

            stopwatch.Reset();
            stopwatch.Start();
            //最后，计算一下中间节点的AABB
            AABBBuilder.BuildAABB(interiorNodes, radixBuilder.leafNodes);
            stopwatch.Stop();
            var t5 = stopwatch.ElapsedMilliseconds;

            //合并叶子节点和中间节点得到可遍历的LBvh
            RadixTreeNode[] LBvh = radixBuilder.CollectNodes(interiorNodes);

            //用于绘制
            debugNodes = LBvh;
            //树的深度
            int depth = radixBuilder.GetDepth(LBvh, 0);

            var lineStart = new Vector3(-5, 0, 0);
            var lineEnd = new Vector3(5, 0, 0);

            var triangles = TraverseUtils.GetIntersectingLeafNodes(LBvh, lineStart, lineEnd);
            var trianglesReal = new List<Triangle>();
            var intersectionPoints = new List<Vector3>();
            foreach (var item in triangles)
            {
                var point = new Vector3();
                int intersecting = TraverseUtils.GetLineTriangleIntersection(lineStart, lineEnd, item, out point);
                if (intersecting == 2)//交点在三角形内部或边界上
                {
                    trianglesReal.Add(item);
                    intersectionPoints.Add(point);
                }
            }
            Mesh mesh = new Mesh();
            Vector3[] meshVertices = new Vector3[trianglesReal.Count * 3];
            int[] meshTriangles = Enumerable.Range(0, trianglesReal.Count * 3).ToArray();
            for (int i = 0; i < trianglesReal.Count; i++)
            {
                var tri = trianglesReal[i];
                meshVertices[i * 3] = tri.v0;
                meshVertices[i * 3 + 1] = tri.v1;
                meshVertices[i * 3 + 2] = tri.v2;
            }
            mesh.vertices = meshVertices;
            mesh.triangles = meshTriangles;
            GameObject triangleObject = new GameObject("Highlighted Triangle");
            MeshFilter meshFilter = triangleObject.AddComponent<MeshFilter>();
            MeshRenderer meshRenderer = triangleObject.AddComponent<MeshRenderer>();
            Material material = new Material(Shader.Find("Standard"));
            material.color = Color.red;
            meshRenderer.material = material;
            meshFilter.mesh = mesh;
            triangleObject.transform.localScale = Vector3.one;

            UnityEngine.Debug.Log($"其中，全局三角形：{t1}ms,\t计算莫顿码：{t2}ms,\t排序：{t3}ms,\t建树：{t4}ms,计算AABB：{t5}ms");
        }

        public void DrawGizmos()
        {
            foreach (var node in debugNodes)
            {
                var aabb = node.aabb;
                Gizmos.DrawWireCube(aabb.center, aabb.size);
            }
            var lineStart = new Vector3(-5, 0, 0);
            var lineEnd = new Vector3(5, 0, 0);
            Gizmos.DrawLine(lineStart, lineEnd);
        }
    }
}
